﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml;

namespace CL.Tools.Common
{
    /// <summary>
    /// 银付宝H5支付
    /// </summary>
    public class YFBH5PayHelper
    {
        /// <summary>
        /// 支付密钥
        /// </summary>
        public string Mch_Key { get; set; }
        /// <summary>
        /// 商户ID
        /// </summary>
        public string Mch_ID { get; set; }
        /// <summary>
        /// 订单预支付请求URL
        /// </summary>
        public string Req_Url { get; set; }
        /// <summary>
        /// 订单查询请求URL
        /// </summary>
        public string Query_Url { get; set; }
        /// <summary>
        /// 订单异步通知URL
        /// </summary>
        public string Notify_Url { get; set; }

        /// <summary>
        /// 应答的参数
        /// </summary>
        protected SortedDictionary<string, string> parameters;

        /// <summary>
        /// debug信息
        /// </summary>
        private string debugInfo;

        /// <summary>
        /// 原始内容
        /// </summary>
        protected string content;

        private string charset = "UTF-8";

        /// <summary>
        /// 获取服务器通知数据方式，进行参数获取
        /// </summary>
        public YFBH5PayHelper()
        {
            parameters = new SortedDictionary<string, string>();
            try
            {
                var config = LoadCfg();
                WriteFile("支付配置信息读取：" + JsonHelper.ObjectToJSON(config), this.parameters);
                if (config != null)
                {
                    this.Mch_ID = config["mch_id"];
                    this.Mch_Key = config["key"];
                    this.Notify_Url = config["notify_url"];
                    this.Query_Url = config["query_url"];
                    this.Req_Url = config["req_url"];
                }
            }
            catch (Exception ex)
            {
                this.setParameter(ex.Message, ex.StackTrace);
                WriteFile("支付配置加载错误", this.parameters);
            }

        }

        /// <summary>
        /// 获取返回内容
        /// </summary>
        /// <returns></returns>
        public string getContent()
        {
            return this.content;
        }
        /// <summary>
        /// 设置返回内容
        /// </summary>
        /// <param name="content">XML内容</param>
        public virtual void setContent(string content)
        {
            this.content = content;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(content);
            XmlNode root = xmlDoc.SelectSingleNode("xml");
            XmlNodeList xnl = root.ChildNodes;

            foreach (XmlNode xnf in xnl)
            {
                this.setParameter(xnf.Name, xnf.InnerText);
            }
        }
        /// <summary>
        /// 设置参数值
        /// </summary>
        /// <param name="parameter">参数名</param>
        /// <param name="parameterValue">参数值</param>
        public void setParameter(string parameter, string parameterValue)
        {
            if (parameter != null && parameter != "")
            {
                if (parameters.ContainsKey(parameter))
                {
                    parameters.Remove(parameter);
                }
                parameters.Add(parameter, parameterValue);
            }
        }
        #region 支付
        /// <summary>
        /// 构造支付参数
        /// </summary>
        /// <param name="orderno"></param>
        /// <param name="ip"></param>
        /// <param name="amout"></param>
        /// <param name="payBody"></param>
        /// <returns></returns>
        public SortedDictionary<string, string> BuildDoPay(string orderno, string ip, string amout, string payBody = "Sycee")
        {
            SortedDictionary<String, String> map = new SortedDictionary<String, String>();
            map.Add("mch_id", this.Mch_ID);
            map.Add("body", HttpUtility.UrlEncode(payBody));
            map.Add("nonce_str", DateTime.Now.ToString("yyyyMMddHHmmss"));
            map.Add("mch_create_ip", ip);
            map.Add("out_trade_no", orderno);
            map.Add("total_fee", amout);
            map.Add("notify_url", this.Notify_Url);
            map.Add("sign", BuildSign(map, this.Mch_Key));
            return map;
        }
        /// <summary>
        /// 获取支付信息
        /// </summary>
        /// <returns></returns>
        public YFTPayResult GetPrePayInfo(string jsonPrePayInfo)
        {
            YFTPayResult PayInfoResult = null;
            if (string.IsNullOrEmpty(jsonPrePayInfo)) return null;
            PayInfoResult = JsonHelper.JSONToObject<YFTPayResult>(jsonPrePayInfo);
            return PayInfoResult;
        }
        #endregion
        /// <summary>
        /// 构造签名
        /// </summary>
        /// <param name="map"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private string BuildSign(SortedDictionary<string, string> map, string key)
        {
            string sign = string.Empty;

            foreach (KeyValuePair<string, string> item in map)
            {
                sign += string.Format("{0}={1}&", item.Key, item.Value);
            }
            if (sign.Length > 0) sign = string.Format("{0}key={1}", sign, key);
            string encryptSign = Utils.MD5(sign);
            return encryptSign;
        }
        /// <summary>
        /// 是否威富通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
        /// </summary>
        /// <returns></returns>
        public virtual Boolean isTenpaySign()
        {
            StringBuilder sb = new StringBuilder();

            ArrayList akeys = new ArrayList(parameters.Keys);
            akeys.Sort();

            foreach (string k in akeys)
            {
                string v = (string)parameters[k];
                if (null != v && "".CompareTo(v) != 0
                    && "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
                {
                    sb.Append(k + "=" + v + "&");
                }
            }

            sb.Append("key=" + this.Mch_Key);
            string sign = Utils.MD5(sb.ToString()).ToLower();

            //debug信息
            this.setDebugInfo(sb.ToString() + " => sign:" + sign);
            return getParameter("sign").ToLower().Equals(sign);
        }
        /// <summary>
        /// 加载配置文件
        /// </summary>
        /// <returns></returns>
        public static Dictionary<String, String> LoadCfg()
        {
            Dictionary<String, String> cfg = new Dictionary<string, string>();
            XmlNode Node = Utils.QueryConfigNode("root/payyfb");
            cfg.Add("mch_id", Node.SelectSingleNode("mchid").InnerText);
            cfg.Add("key", Node.SelectSingleNode("mchkey").InnerText);
            cfg.Add("notify_url", Node.SelectSingleNode("notifyurl").InnerText);
            cfg.Add("query_url", Node.SelectSingleNode("queryurl").InnerText);
            cfg.Add("req_url", Node.SelectSingleNode("requrl").InnerText);
            return cfg;
        }
        /// <summary>
        /// 保存接口返回结果到文件中
        /// </summary>
        /// <param name="_param">接口结果</param>
        public static void WriteFile(string title, SortedDictionary<string, string> _param)
        {
            string resFilePath = Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ApplicationBase)
                                + Path.DirectorySeparatorChar + "result.txt";
            if (!File.Exists(resFilePath))
            {
                using (StreamWriter sw = new StreamWriter(resFilePath))
                {
                    sw.WriteLine("=====================" + title + "=====================");
                    foreach (var de in _param)
                    {
                        sw.WriteLine("key:" + de.Key.ToString() + " value:" + de.Value.ToString());
                    }
                }
            }
            else
            {
                using (StreamWriter sw = File.AppendText(resFilePath))
                {
                    sw.WriteLine("=====================" + title + "=====================");
                    foreach (var de in _param)
                    {
                        sw.WriteLine("key:" + de.Key.ToString() + " value:" + de.Value.ToString());
                    }
                }
            }
        }
        /// <summary>
        /// 获取返回的所有参数
        /// </summary>
        /// <returns></returns>
        public SortedDictionary<string, string> GetAllParameters()
        {
            return this.parameters;
        }

        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <param name="parameter">参数名</param>
        /// <returns></returns>
        public string getParameter(string parameter)
        {
            string s = (string)parameters[parameter];
            return (null == s) ? "" : s;
        }
        /// <summary>
        /// 设置debug信息
        /// </summary>
        /// <param name="debugInfo"></param>
        protected void setDebugInfo(String debugInfo)
        { this.debugInfo = debugInfo; }
        /// <summary>
        /// 获取编码
        /// </summary>
        /// <returns></returns>
        protected virtual string getCharset()
        {
            return this.charset;
        }

        /// <summary>
        /// 将Hashtable参数传为XML
        /// </summary>
        /// <param name="_params"></param>
        /// <returns></returns>
        public static string toXml(Hashtable _params)
        {
            StringBuilder sb = new StringBuilder("<xml>");
            foreach (DictionaryEntry de in _params)
            {
                string key = de.Key.ToString();
                sb.Append("<").Append(key).Append("><![CDATA[").Append(de.Value.ToString()).Append("]]></").Append(key).Append(">");
            }

            return sb.Append("</xml>").ToString();
        }

        /// <summary>
        /// 生成32位随机数
        /// </summary>
        /// <returns></returns>
        public static string random()
        {
            char[] constant = {'0','1','2','3','4','5','6','7','8','9',
                               'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
                               'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
            StringBuilder sb = new StringBuilder(32);
            Random rd = new Random();
            for (int i = 0; i < 32; i++)
            {
                sb.Append(constant[rd.Next(62)]);
            }
            return sb.ToString();
        }
    }

    public class YFTPayResult
    {
        /// <summary>
        /// 支付参数
        /// </summary>
        public YFTPayParams pay_params { get; set; }
        /// <summary>
        /// 返回消息
        /// </summary>
        public string return_msg { get; set; }
        /// <summary>
        /// 返回状态码
        /// </summary>
        public string return_code { get; set; }
    }

    public class YFTPayParams
    {
        /// <summary>
        /// 支付订单号
        /// </summary>
        public string out_trade_no { get; set; }
        /// <summary>
        /// 支付链接
        /// </summary>
        public string pay_info { get; set; }
        /// <summary>
        /// 支付金额(分)
        /// </summary>
        public string total_fee { get; set; }
        /// <summary>
        /// 商户ID
        /// </summary>
        public string mch_id { get; set; }
    }
}